The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
Changes 010
LICENSE 33
MANIFEST 08
META.json 4257
META.yml 4254
Makefile.PL 26
README 22
dist.ini 21
lib/Log/Dispatchouli/Global.pm 0278
lib/Log/Dispatchouli/Proxy.pm 35
lib/Log/Dispatchouli.pm 764
t/basic.t 16
t/env-value.t 044
t/global-subclass.t 040
t/global.t 054
t/lib/DDR/Child.pm 011
t/lib/DDR/Parent.pm 012
t/lib/SDR/Child.pm 011
t/lib/SDR/Parent.pm 015
t/proxy.t 28
20 files changed (This is a version diff) 106689
@@ -1,5 +1,15 @@
 Revision history for Log-Dispatchouli
 
+2.002     2011-01-14 17:51:16 America/New_York
+          add env_value and env_prefix methods
+
+2.001     2011-01-13 12:45:05 America/New_York
+          greatly expanded tests and documentation for L::D::Global
+
+          L::D now has "string_flogger" method to provide an alternate flogger
+
+2.000     2010-11-23 18:48:53 America/New_York
+
 1.102350  2010-08-23 08:55:17 America/New_York
           fix a bug in generating tempdirs for file logging (thanks, Sawyer X)
 
@@ -1,4 +1,4 @@
-This software is copyright (c) 2010 by Ricardo SIGNES.
+This software is copyright (c) 2011 by Ricardo SIGNES.
 
 This is free software; you can redistribute it and/or modify it under
 the same terms as the Perl 5 programming language system itself.
@@ -12,7 +12,7 @@ b) the "Artistic License"
 
 --- The GNU General Public License, Version 1, February 1989 ---
 
-This software is Copyright (c) 2010 by Ricardo SIGNES.
+This software is Copyright (c) 2011 by Ricardo SIGNES.
 
 This is free software, licensed under:
 
@@ -270,7 +270,7 @@ That's all there is to it!
 
 --- The Artistic License 1.0 ---
 
-This software is Copyright (c) 2010 by Ricardo SIGNES.
+This software is Copyright (c) 2011 by Ricardo SIGNES.
 
 This is free software, licensed under:
 
@@ -7,7 +7,15 @@ Makefile.PL
 README
 dist.ini
 lib/Log/Dispatchouli.pm
+lib/Log/Dispatchouli/Global.pm
 lib/Log/Dispatchouli/Proxy.pm
 t/basic.t
+t/env-value.t
+t/global-subclass.t
+t/global.t
+t/lib/DDR/Child.pm
+t/lib/DDR/Parent.pm
+t/lib/SDR/Child.pm
+t/lib/SDR/Parent.pm
 t/proxy.t
 t/release-pod-syntax.t
@@ -4,7 +4,7 @@
       "Ricardo SIGNES <rjbs@cpan.org>"
    ],
    "dynamic_config" : 0,
-   "generated_by" : "Dist::Zilla version 4.102220, CPAN::Meta::Converter version 2.102160",
+   "generated_by" : "Dist::Zilla version 4.200000, CPAN::Meta::Converter version 2.102400",
    "license" : [
       "perl_5"
    ],
@@ -22,6 +22,7 @@
       "runtime" : {
          "requires" : {
             "Carp" : 0,
+            "File::Spec" : 0,
             "Log::Dispatch" : 0,
             "Log::Dispatch::Array" : 0,
             "Log::Dispatch::File" : 0,
@@ -30,6 +31,8 @@
             "Params::Util" : 0,
             "Scalar::Util" : 0,
             "String::Flogger" : 0,
+            "Sub::Exporter" : 0,
+            "Sub::Exporter::GlobExporter" : "0.002",
             "Sys::Syslog" : "0.16",
             "Try::Tiny" : "0.04",
             "overload" : 0
@@ -38,7 +41,8 @@
       "test" : {
          "requires" : {
             "Test::Deep" : 0,
-            "Test::More" : "0.88"
+            "Test::Fatal" : 0,
+            "Test::More" : "0.96"
          }
       }
    },
@@ -49,174 +53,185 @@
          "url" : "git://git.codesimply.com/Log-Dispatchouli.git"
       }
    },
-   "version" : "1.102350",
+   "version" : "2.002",
    "x_Dist_Zilla" : {
       "plugins" : [
          {
             "class" : "Dist::Zilla::Plugin::GatherDir",
             "name" : "@RJBS/@Basic/GatherDir",
-            "version" : "4.102220"
+            "version" : "4.200000"
          },
          {
             "class" : "Dist::Zilla::Plugin::PruneCruft",
             "name" : "@RJBS/@Basic/PruneCruft",
-            "version" : "4.102220"
+            "version" : "4.200000"
          },
          {
             "class" : "Dist::Zilla::Plugin::ManifestSkip",
             "name" : "@RJBS/@Basic/ManifestSkip",
-            "version" : "4.102220"
+            "version" : "4.200000"
          },
          {
             "class" : "Dist::Zilla::Plugin::MetaYAML",
             "name" : "@RJBS/@Basic/MetaYAML",
-            "version" : "4.102220"
+            "version" : "4.200000"
          },
          {
             "class" : "Dist::Zilla::Plugin::License",
             "name" : "@RJBS/@Basic/License",
-            "version" : "4.102220"
+            "version" : "4.200000"
          },
          {
             "class" : "Dist::Zilla::Plugin::Readme",
             "name" : "@RJBS/@Basic/Readme",
-            "version" : "4.102220"
+            "version" : "4.200000"
          },
          {
             "class" : "Dist::Zilla::Plugin::ExtraTests",
             "name" : "@RJBS/@Basic/ExtraTests",
-            "version" : "4.102220"
+            "version" : "4.200000"
          },
          {
             "class" : "Dist::Zilla::Plugin::ExecDir",
             "name" : "@RJBS/@Basic/ExecDir",
-            "version" : "4.102220"
+            "version" : "4.200000"
          },
          {
             "class" : "Dist::Zilla::Plugin::ShareDir",
             "name" : "@RJBS/@Basic/ShareDir",
-            "version" : "4.102220"
+            "version" : "4.200000"
          },
          {
             "class" : "Dist::Zilla::Plugin::MakeMaker",
             "name" : "@RJBS/@Basic/MakeMaker",
-            "version" : "4.102220"
+            "version" : "4.200000"
          },
          {
             "class" : "Dist::Zilla::Plugin::Manifest",
             "name" : "@RJBS/@Basic/Manifest",
-            "version" : "4.102220"
+            "version" : "4.200000"
          },
          {
             "class" : "Dist::Zilla::Plugin::TestRelease",
             "name" : "@RJBS/@Basic/TestRelease",
-            "version" : "4.102220"
+            "version" : "4.200000"
          },
          {
             "class" : "Dist::Zilla::Plugin::ConfirmRelease",
             "name" : "@RJBS/@Basic/ConfirmRelease",
-            "version" : "4.102220"
+            "version" : "4.200000"
          },
          {
             "class" : "Dist::Zilla::Plugin::UploadToCPAN",
             "name" : "@RJBS/@Basic/UploadToCPAN",
-            "version" : "4.102220"
+            "version" : "4.200000"
          },
          {
-            "class" : "Dist::Zilla::Plugin::AutoPrereq",
-            "name" : "@RJBS/AutoPrereq",
-            "version" : "4.102220"
+            "class" : "Dist::Zilla::Plugin::AutoPrereqs",
+            "name" : "@RJBS/AutoPrereqs",
+            "version" : "4.200000"
          },
          {
-            "class" : "Dist::Zilla::Plugin::AutoVersion",
-            "name" : "@RJBS/AutoVersion",
-            "version" : "4.102220"
+            "class" : "Dist::Zilla::Plugin::Git::NextVersion",
+            "name" : "@RJBS/Git::NextVersion",
+            "version" : "1.103520"
          },
          {
             "class" : "Dist::Zilla::Plugin::PkgVersion",
             "name" : "@RJBS/PkgVersion",
-            "version" : "4.102220"
+            "version" : "4.200000"
          },
          {
             "class" : "Dist::Zilla::Plugin::MetaConfig",
             "name" : "@RJBS/MetaConfig",
-            "version" : "4.102220"
+            "version" : "4.200000"
          },
          {
             "class" : "Dist::Zilla::Plugin::MetaJSON",
             "name" : "@RJBS/MetaJSON",
-            "version" : "4.102220"
+            "version" : "4.200000"
          },
          {
             "class" : "Dist::Zilla::Plugin::NextRelease",
             "name" : "@RJBS/NextRelease",
-            "version" : "4.102220"
+            "version" : "4.200000"
          },
          {
             "class" : "Dist::Zilla::Plugin::PodSyntaxTests",
             "name" : "@RJBS/PodSyntaxTests",
-            "version" : "4.102220"
+            "version" : "4.200000"
          },
          {
             "class" : "Dist::Zilla::Plugin::Repository",
             "name" : "@RJBS/Repository",
-            "version" : "0.13"
+            "version" : "0.17"
+         },
+         {
+            "class" : "Dist::Zilla::Plugin::Prereqs",
+            "config" : {
+               "Dist::Zilla::Plugin::Prereqs" : {
+                  "phase" : "test",
+                  "type" : "requires"
+               }
+            },
+            "name" : "@RJBS/TestMoreWithSubtests",
+            "version" : "4.200000"
          },
          {
             "class" : "Dist::Zilla::Plugin::PodWeaver",
             "name" : "@RJBS/PodWeaver",
-            "version" : "3.101640"
+            "version" : "3.101641"
          },
          {
             "class" : "Dist::Zilla::Plugin::Git::Check",
             "name" : "@RJBS/@Git/Check",
-            "version" : "1.102090"
+            "version" : "1.103520"
          },
          {
             "class" : "Dist::Zilla::Plugin::Git::Commit",
             "name" : "@RJBS/@Git/Commit",
-            "version" : "1.102090"
+            "version" : "1.103520"
          },
          {
             "class" : "Dist::Zilla::Plugin::Git::Tag",
             "name" : "@RJBS/@Git/Tag",
-            "version" : "1.102090"
+            "version" : "1.103520"
          },
          {
             "class" : "Dist::Zilla::Plugin::Git::Push",
             "name" : "@RJBS/@Git/Push",
-            "version" : "1.102090"
+            "version" : "1.103520"
          },
          {
-            "class" : "Dist::Zilla::Plugin::Prereq",
+            "class" : "Dist::Zilla::Plugin::Prereqs",
             "config" : {
                "Dist::Zilla::Plugin::Prereqs" : {
                   "phase" : "runtime",
                   "type" : "requires"
                }
             },
-            "name" : "Prereq",
-            "version" : "4.102220"
+            "name" : "Prereqs",
+            "version" : "4.200000"
          },
          {
             "class" : "Dist::Zilla::Plugin::FinderCode",
             "name" : ":InstallModules",
-            "version" : "4.102220"
+            "version" : "4.200000"
          },
          {
             "class" : "Dist::Zilla::Plugin::FinderCode",
             "name" : ":TestFiles",
-            "version" : "4.102220"
+            "version" : "4.200000"
          },
          {
             "class" : "Dist::Zilla::Plugin::FinderCode",
             "name" : ":ExecFiles",
-            "version" : "4.102220"
+            "version" : "4.200000"
          },
          {
             "class" : "Dist::Zilla::Plugin::FinderCode",
             "name" : ":ShareFiles",
-            "version" : "4.102220"
+            "version" : "4.200000"
          }
       ],
       "zilla" : {
@@ -224,7 +239,7 @@
          "config" : {
             "is_trial" : 0
          },
-         "version" : "4.102220"
+         "version" : "4.200000"
       }
    }
 }
@@ -4,11 +4,12 @@ author:
   - 'Ricardo SIGNES <rjbs@cpan.org>'
 build_requires:
   Test::Deep: 0
-  Test::More: 0.88
+  Test::Fatal: 0
+  Test::More: 0.96
 configure_requires:
   ExtUtils::MakeMaker: 6.31
 dynamic_config: 0
-generated_by: 'Dist::Zilla version 4.102220, CPAN::Meta::Converter version 2.102160'
+generated_by: 'Dist::Zilla version 4.200000, CPAN::Meta::Converter version 2.102400'
 license: perl
 meta-spec:
   url: http://module-build.sourceforge.net/META-spec-v1.4.html
@@ -16,6 +17,7 @@ meta-spec:
 name: Log-Dispatchouli
 requires:
   Carp: 0
+  File::Spec: 0
   Log::Dispatch: 0
   Log::Dispatch::Array: 0
   Log::Dispatch::File: 0
@@ -24,148 +26,158 @@ requires:
   Params::Util: 0
   Scalar::Util: 0
   String::Flogger: 0
+  Sub::Exporter: 0
+  Sub::Exporter::GlobExporter: 0.002
   Sys::Syslog: 0.16
   Try::Tiny: 0.04
   overload: 0
 resources:
   repository: git://git.codesimply.com/Log-Dispatchouli.git
-version: 1.102350
+version: 2.002
 x_Dist_Zilla:
   plugins:
     -
       class: Dist::Zilla::Plugin::GatherDir
       name: '@RJBS/@Basic/GatherDir'
-      version: 4.102220
+      version: 4.200000
     -
       class: Dist::Zilla::Plugin::PruneCruft
       name: '@RJBS/@Basic/PruneCruft'
-      version: 4.102220
+      version: 4.200000
     -
       class: Dist::Zilla::Plugin::ManifestSkip
       name: '@RJBS/@Basic/ManifestSkip'
-      version: 4.102220
+      version: 4.200000
     -
       class: Dist::Zilla::Plugin::MetaYAML
       name: '@RJBS/@Basic/MetaYAML'
-      version: 4.102220
+      version: 4.200000
     -
       class: Dist::Zilla::Plugin::License
       name: '@RJBS/@Basic/License'
-      version: 4.102220
+      version: 4.200000
     -
       class: Dist::Zilla::Plugin::Readme
       name: '@RJBS/@Basic/Readme'
-      version: 4.102220
+      version: 4.200000
     -
       class: Dist::Zilla::Plugin::ExtraTests
       name: '@RJBS/@Basic/ExtraTests'
-      version: 4.102220
+      version: 4.200000
     -
       class: Dist::Zilla::Plugin::ExecDir
       name: '@RJBS/@Basic/ExecDir'
-      version: 4.102220
+      version: 4.200000
     -
       class: Dist::Zilla::Plugin::ShareDir
       name: '@RJBS/@Basic/ShareDir'
-      version: 4.102220
+      version: 4.200000
     -
       class: Dist::Zilla::Plugin::MakeMaker
       name: '@RJBS/@Basic/MakeMaker'
-      version: 4.102220
+      version: 4.200000
     -
       class: Dist::Zilla::Plugin::Manifest
       name: '@RJBS/@Basic/Manifest'
-      version: 4.102220
+      version: 4.200000
     -
       class: Dist::Zilla::Plugin::TestRelease
       name: '@RJBS/@Basic/TestRelease'
-      version: 4.102220
+      version: 4.200000
     -
       class: Dist::Zilla::Plugin::ConfirmRelease
       name: '@RJBS/@Basic/ConfirmRelease'
-      version: 4.102220
+      version: 4.200000
     -
       class: Dist::Zilla::Plugin::UploadToCPAN
       name: '@RJBS/@Basic/UploadToCPAN'
-      version: 4.102220
+      version: 4.200000
     -
-      class: Dist::Zilla::Plugin::AutoPrereq
-      name: '@RJBS/AutoPrereq'
-      version: 4.102220
+      class: Dist::Zilla::Plugin::AutoPrereqs
+      name: '@RJBS/AutoPrereqs'
+      version: 4.200000
     -
-      class: Dist::Zilla::Plugin::AutoVersion
-      name: '@RJBS/AutoVersion'
-      version: 4.102220
+      class: Dist::Zilla::Plugin::Git::NextVersion
+      name: '@RJBS/Git::NextVersion'
+      version: 1.103520
     -
       class: Dist::Zilla::Plugin::PkgVersion
       name: '@RJBS/PkgVersion'
-      version: 4.102220
+      version: 4.200000
     -
       class: Dist::Zilla::Plugin::MetaConfig
       name: '@RJBS/MetaConfig'
-      version: 4.102220
+      version: 4.200000
     -
       class: Dist::Zilla::Plugin::MetaJSON
       name: '@RJBS/MetaJSON'
-      version: 4.102220
+      version: 4.200000
     -
       class: Dist::Zilla::Plugin::NextRelease
       name: '@RJBS/NextRelease'
-      version: 4.102220
+      version: 4.200000
     -
       class: Dist::Zilla::Plugin::PodSyntaxTests
       name: '@RJBS/PodSyntaxTests'
-      version: 4.102220
+      version: 4.200000
     -
       class: Dist::Zilla::Plugin::Repository
       name: '@RJBS/Repository'
-      version: 0.13
+      version: 0.17
+    -
+      class: Dist::Zilla::Plugin::Prereqs
+      config:
+        Dist::Zilla::Plugin::Prereqs:
+          phase: test
+          type: requires
+      name: '@RJBS/TestMoreWithSubtests'
+      version: 4.200000
     -
       class: Dist::Zilla::Plugin::PodWeaver
       name: '@RJBS/PodWeaver'
-      version: 3.101640
+      version: 3.101641
     -
       class: Dist::Zilla::Plugin::Git::Check
       name: '@RJBS/@Git/Check'
-      version: 1.102090
+      version: 1.103520
     -
       class: Dist::Zilla::Plugin::Git::Commit
       name: '@RJBS/@Git/Commit'
-      version: 1.102090
+      version: 1.103520
     -
       class: Dist::Zilla::Plugin::Git::Tag
       name: '@RJBS/@Git/Tag'
-      version: 1.102090
+      version: 1.103520
     -
       class: Dist::Zilla::Plugin::Git::Push
       name: '@RJBS/@Git/Push'
-      version: 1.102090
+      version: 1.103520
     -
-      class: Dist::Zilla::Plugin::Prereq
+      class: Dist::Zilla::Plugin::Prereqs
       config:
         Dist::Zilla::Plugin::Prereqs:
           phase: runtime
           type: requires
-      name: Prereq
-      version: 4.102220
+      name: Prereqs
+      version: 4.200000
     -
       class: Dist::Zilla::Plugin::FinderCode
       name: ':InstallModules'
-      version: 4.102220
+      version: 4.200000
     -
       class: Dist::Zilla::Plugin::FinderCode
       name: ':TestFiles'
-      version: 4.102220
+      version: 4.200000
     -
       class: Dist::Zilla::Plugin::FinderCode
       name: ':ExecFiles'
-      version: 4.102220
+      version: 4.200000
     -
       class: Dist::Zilla::Plugin::FinderCode
       name: ':ShareFiles'
-      version: 4.102220
+      version: 4.200000
   zilla:
     class: Dist::Zilla::Dist::Builder
     config:
       is_trial: 0
-    version: 4.102220
+    version: 4.200000
@@ -13,7 +13,8 @@ my %WriteMakefileArgs = (
   'AUTHOR' => 'Ricardo SIGNES <rjbs@cpan.org>',
   'BUILD_REQUIRES' => {
     'Test::Deep' => '0',
-    'Test::More' => '0.88'
+    'Test::Fatal' => '0',
+    'Test::More' => '0.96'
   },
   'CONFIGURE_REQUIRES' => {
     'ExtUtils::MakeMaker' => '6.31'
@@ -24,6 +25,7 @@ my %WriteMakefileArgs = (
   'NAME' => 'Log::Dispatchouli',
   'PREREQ_PM' => {
     'Carp' => '0',
+    'File::Spec' => '0',
     'Log::Dispatch' => '0',
     'Log::Dispatch::Array' => '0',
     'Log::Dispatch::File' => '0',
@@ -32,11 +34,13 @@ my %WriteMakefileArgs = (
     'Params::Util' => '0',
     'Scalar::Util' => '0',
     'String::Flogger' => '0',
+    'Sub::Exporter' => '0',
+    'Sub::Exporter::GlobExporter' => '0.002',
     'Sys::Syslog' => '0.16',
     'Try::Tiny' => '0.04',
     'overload' => '0'
   },
-  'VERSION' => '1.102350',
+  'VERSION' => '2.002',
   'test' => {
     'TESTS' => 't/*.t'
   }
@@ -1,11 +1,11 @@
 
 
 This archive contains the distribution Log-Dispatchouli,
-version 1.102350:
+version 2.002:
 
   a simple wrapper around Log::Dispatch
 
-This software is copyright (c) 2010 by Ricardo SIGNES.
+This software is copyright (c) 2011 by Ricardo SIGNES.
 
 This is free software; you can redistribute it and/or modify it under
 the same terms as the Perl 5 programming language system itself.
@@ -4,7 +4,6 @@ license = Perl_5
 copyright_holder = Ricardo SIGNES
 
 [@RJBS]
-version = 1
 
-[Prereq]
+[Prereqs]
 Sys::Syslog = 0.16 ; native socket type
@@ -0,0 +1,278 @@
+use strict;
+use warnings;
+package Log::Dispatchouli::Global;
+BEGIN {
+  $Log::Dispatchouli::Global::VERSION = '2.002';
+}
+# ABSTRACT: a system for sharing a global, dynamically-scoped logger
+
+use Carp ();
+use Log::Dispatchouli;
+use Scalar::Util ();
+
+use Sub::Exporter::GlobExporter 0.002 qw(glob_exporter); # pass-through args
+use Sub::Exporter -setup => {
+  collectors => {
+    '$Logger' => glob_exporter(Logger => \'_build_logger'),
+  },
+};
+
+
+sub logger_globref {
+  no warnings 'once';
+  \*Logger;
+}
+
+sub current_logger {
+  my ($self) = @_;
+
+  my $globref = $self->logger_globref;
+
+  unless (defined $$$globref) {
+    $$$globref = $self->default_logger;
+  }
+
+  return $$$globref;
+}
+
+
+sub default_logger {
+  my ($self) = @_;
+
+  my $ref = $self->default_logger_ref;
+
+  $$ref ||= $self->default_logger_class->new(
+    $self->default_logger_args
+  );
+}
+
+
+sub default_logger_class { 'Log::Dispatchouli' }
+
+
+sub default_logger_args {
+  return {
+    ident     => "default/$0",
+    facility  => undef,
+  }
+}
+
+
+my %default_logger_for_glob;
+
+sub default_logger_ref {
+  my ($self) = @_;
+
+  my $glob = $self->logger_globref;
+  my $addr = Scalar::Util::refaddr($glob);
+  return \$default_logger_for_glob{ $addr };
+}
+
+sub _build_logger {
+  my ($self, $arg) = @_;
+
+  my $globref = $self->logger_globref;
+  my $default = $self->default_logger;
+
+  my $Logger  = $$$globref;
+
+  if ($arg and $arg->{init}) {
+    if (
+      $Logger
+      and
+      Scalar::Util::refaddr($Logger) != Scalar::Util::refaddr($default)
+    ) {
+      Carp::confess("attempted to initialize $self logger twice");
+    }
+
+    $$$globref = $self->default_logger_class->new($arg->{init});
+  } else {
+    $$$globref ||= $default;
+  }
+
+  return $globref;
+}
+
+
+1;
+
+__END__
+=pod
+
+=head1 NAME
+
+Log::Dispatchouli::Global - a system for sharing a global, dynamically-scoped logger
+
+=head1 VERSION
+
+version 2.002
+
+=head1 DESCRIPTION
+
+B<Warning>: This interface is still experimental.
+
+Log::Dispatchouli::Global is a framework for a global logger object. In your
+top-level programs that are actually executed, you'd add something like this:
+
+  use Log::Dispatchouli::Global '$Logger' => {
+    init => {
+      ident     => 'My::Daemon',
+      facility  => 'local2',
+      to_stdout => 1,
+    },
+  };
+
+This will import a C<$Logger> into your program, and more importantly will
+initialize it with a new L<Log::Dispatchouli> object created by passing the
+value for the C<init> parameter to Log::Dispatchouli's C<new> method.
+
+Much of the rest of your program, across various libraries, can then just use
+this:
+
+  use Log::Dispatchouli::Global '$Logger';
+
+  sub whatever {
+    ...
+
+    $Logger->log("about to do something");
+
+    local $Logger = $Logger->proxy({ proxy_prefix => "whatever: " });
+
+    for (@things) {
+      $Logger->log([ "doing thing %s", $_ ]);
+      ...
+    }
+  }
+
+This eliminates the need to pass around what is effectively a global, while
+still allowing it to be specialized withing certain contexts of your program.
+
+B<Warning!>  Although you I<could> just use Log::Dispatchouli::Global as your
+shared logging library, you almost I<certainly> want to write a subclass that
+will only be shared amongst your application's classes.
+Log::Dispatchouli::Global is meant to be subclassed and shared only within
+controlled systems.  Remember, I<sharing your state with code you don't
+control is dangerous>.
+
+=head1 USING
+
+In general, you will either be using a Log::Dispatchouli::Global class to get
+a C<$Logger> or to initialize it (and then get C<$Logger>).  These are both
+demonstrated above.  Also, when importing C<$Logger> you may request it be
+imported under a different name:
+
+  use Log::Dispatchouli::Global '$Logger' => { -as => 'L' };
+
+  $L->log( ... );
+
+There is only one class method that you are likely to use: C<current_logger>.
+This provides the value of the shared logger from the caller's context,
+initializing it to a default if needed.  Even this method is unlikely to be
+required frequently, but it I<does> allow users to I<see> C<$Logger> without
+importing it.
+
+=head1 SUBCLASSING
+
+Before using Log::Dispatchouli::Global in your application, you should subclass
+it.  When you subclass it, you should provide the following methods:
+
+=head2 logger_globref
+
+This method should return a globref in which the shared logger will be stored.
+Subclasses will be in their own package, so barring any need for cleverness,
+every implementation of this method can look like the following:
+
+  sub logger_globref { no warnings 'once'; return \*Logger }
+
+=head2 default_logger
+
+If no logger has been initialized, but something tries to log, it gets the
+default logger, created by calling this method.
+
+The default implementation calls C<new> on the C<default_logger_class> with the
+result of C<default_logger_args> as the arguments.
+
+=head2 default_logger_class
+
+This returns the class on which C<new> will be called when initializing a
+logger, either from the C<init> argument when importing or the default logger.
+
+Its default value is Log::Dispatchouli.
+
+=head2 default_logger_args
+
+If no logger has been initialized, but something tries to log, it gets the
+default logger, created by calling C<new> on the C<default_logger_class> and
+passing the results of calling this method.
+
+Its default return value creates a sink, so that anything logged without an
+initialized logger is lost.
+
+=head2 default_logger_ref
+
+This method returns a scalar reference in which the cached default value is
+stored for comparison.  This is used when someone tries to C<init> the global.
+When someone tries to initialize the global logger, and it's already set, then:
+
+=over 4
+
+=item *
+
+if the current value is the same as the default, the new value is set
+
+=item *
+
+if the current value is I<not> the same as the default, we die
+
+=back
+
+Since you want the default to be isolated to your application's logger, the
+default behavior is default loggers are associated with the glob reference to
+which the default might be assigned.  It is recommended that you replace this
+method to return a shared, private variable for your subclasses, by putting the
+following code in the base class for your Log::Dispatchouli::Global classes:
+
+  my $default_logger;
+  sub default_logger_ref { \$default_logger };
+
+=head1 COOKBOOK
+
+=head2 Common Logger Recipes
+
+Say you often use the same configuration for one kind of program, like
+automated tests.  You've already written your own subclass to get your own
+storage and defaults, maybe C<MyApp::Logger>.
+
+You can't just write a subclass with a different default, because if another
+class using the same global has set the global with I<its> default, yours won't
+be honored.  You don't just want this new value to be the default, you want it
+to be I<the> logger.  What you want to do in this case is to initialize your
+logger normally, then reexport it, like this:
+
+  package MyApp::Logger::Test;
+  use parent 'MyApp::Logger';
+
+  use MyApp::Logger '$Logger' => {
+    init => {
+      ident    => "Tester($0)",
+      to_self  => 1,
+      facility => undef,
+    },
+  };
+
+This will set up the logger and re-export it, and will properly die if anything
+else attempts to initialize the logger to something else.
+
+=head1 AUTHOR
+
+Ricardo SIGNES <rjbs@cpan.org>
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2011 by Ricardo SIGNES.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
+
@@ -2,7 +2,7 @@ use strict;
 use warnings;
 package Log::Dispatchouli::Proxy;
 BEGIN {
-  $Log::Dispatchouli::Proxy::VERSION = '1.102350';
+  $Log::Dispatchouli::Proxy::VERSION = '2.002';
 }
 # ABSTRACT: a simple wrapper around Log::Dispatch
 
@@ -38,6 +38,8 @@ sub proxy  {
 sub parent { $_[0]{parent} }
 sub logger { $_[0]{logger} }
 
+sub ident  { $_[0]{logger}->ident }
+
 sub set_prefix   { $_[0]{prefix} = $_[1] }
 sub get_prefix   { $_[0]{prefix} }
 sub clear_prefix { undef $_[0]{prefix} }
@@ -117,7 +119,7 @@ Log::Dispatchouli::Proxy - a simple wrapper around Log::Dispatch
 
 =head1 VERSION
 
-version 1.102350
+version 2.002
 
 =head1 DESCRIPTION
 
@@ -150,7 +152,7 @@ Ricardo SIGNES <rjbs@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
-This software is copyright (c) 2010 by Ricardo SIGNES.
+This software is copyright (c) 2011 by Ricardo SIGNES.
 
 This is free software; you can redistribute it and/or modify it under
 the same terms as the Perl 5 programming language system itself.
@@ -2,11 +2,12 @@ use strict;
 use warnings;
 package Log::Dispatchouli;
 BEGIN {
-  $Log::Dispatchouli::VERSION = '1.102350';
+  $Log::Dispatchouli::VERSION = '2.002';
 }
 # ABSTRACT: a simple wrapper around Log::Dispatch
 
 use Carp ();
+use File::Spec ();
 use Log::Dispatch;
 use Params::Util qw(_ARRAY0 _HASH0 _CODELIKE);
 use Scalar::Util qw(blessed weaken);
@@ -43,7 +44,7 @@ sub new {
   if ($arg->{to_file}) {
     require Log::Dispatch::File;
     my $log_file = File::Spec->catfile(
-      ($ENV{DISPATCHOULI_PATH} || File::Spec->tmpdir),
+      ($self->env_value('PATH') || File::Spec->tmpdir),
       sprintf('%s.%04u%02u%02u',
         $ident,
         ((localtime)[5] + 1900),
@@ -67,7 +68,7 @@ sub new {
     );
   }
 
-  if ($arg->{facility} and not $ENV{DISPATCHOULI_NOSYSLOG}) {
+  if ($arg->{facility} and not $self->env_value('NOSYSLOG')) {
     require Log::Dispatch::Syslog;
     $log->add(
       Log::Dispatch::Syslog->new(
@@ -115,10 +116,11 @@ sub new {
 
   $self->{dispatcher} = $log;
   $self->{prefix} = $arg->{prefix};
+  $self->{ident}  = $ident;
 
   $self->{debug}  = exists $arg->{debug}
                   ? ($arg->{debug} ? 1 : 0)
-                  : ($ENV{DISPATCHOULI_DEBUG} ? 1 : 0);
+                  : ($self->env_value('DEBUG') ? 1 : 0);
 
   $self->{fail_fatal} = exists $arg->{fail_fatal} ? $arg->{fail_fatal} : 1;
 
@@ -136,7 +138,8 @@ sub log {
 
   if ($arg->{fatal} or ! $self->get_muted) {
     try {
-      my @flogged = map {; String::Flogger->flog($_) } @rest;
+      my $flogger = $self->string_flogger;
+      my @flogged = map {; $flogger->flog($_) } @rest;
       $message    = @flogged > 1 ? $self->_join(\@flogged) : $flogged[0];
 
       my $prefix  = _ARRAY0($arg->{prefix})
@@ -223,6 +226,30 @@ sub clear_prefix { $_[0]->unset_prefix     }
 sub unset_prefix { undef $_[0]->{prefix}   }
 
 
+sub ident { $_[0]{ident} }
+
+
+
+sub string_flogger { 'String::Flogger' }
+
+
+sub env_prefix { return; }
+
+
+sub env_value {
+  my ($self, $suffix) = @_;
+
+  my @path = grep { defined } ($self->env_prefix, 'DISPATCHOULI');
+
+  for my $prefix (@path) {
+    my $name = join q{_}, $prefix, $suffix;
+    return $ENV{ $name } if defined $ENV{ $name };
+  }
+
+  return;
+}
+
+
 sub new_tester {
   my ($class, $arg) = @_;
   $arg ||= {};
@@ -303,7 +330,7 @@ Log::Dispatchouli - a simple wrapper around Log::Dispatch
 
 =head1 VERSION
 
-version 1.102350
+version 2.002
 
 =head1 SYNOPSIS
 
@@ -452,6 +479,10 @@ This method changes the prefix.  See L<Logger Prefix|/LOGGER PREFIX>.
 This method clears any set logger prefix.  (It can also be called as
 C<unset_prefix>, but this is deprecated.  See L<Logger Prefix|/LOGGER PREFIX>.
 
+=head2 ident
+
+This method returns the logger's ident.
+
 =head2 dispatcher
 
 This returns the underlying Log::Dispatch object.  This is not the method
@@ -500,6 +531,32 @@ settings, which accumulate.  So:
 
   Batch 123: Subsystem 12: Page 9: Paragraph 6: Done.
 
+=head1 METHODS FOR SUBCLASSING
+
+=head2 string_flogger
+
+This method returns the thing on which F<flog> will be called to format log
+messages.  By default, it just returns C<String::Flogger>
+
+=head2 env_prefix
+
+This method should return a string used as a prefix to find environment
+variables that affect the logger's behavior.  For example, if this method
+returns C<XYZZY> then when checking the environment for a default value for the
+C<debug> parameter, Log::Dispatchouli will first check C<XYZZY_DEBUG>, then
+C<DISPATCHOULI_DEBUG>.
+
+By default, this method returns C<()>, which means no extra environment
+variable is checked.
+
+=head2 env_value
+
+  my $value = $logger->env_value('DEBUG');
+
+This method returns the value for the environment variable suffix given.  For
+example, the example given, calling with C<DEBUG> will check
+C<DISPATCHOULI_DEBUG>.
+
 =head1 METHODS FOR TESTING
 
 =head2 new_tester
@@ -605,7 +662,7 @@ Ricardo SIGNES <rjbs@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
-This software is copyright (c) 2010 by Ricardo SIGNES.
+This software is copyright (c) 2011 by Ricardo SIGNES.
 
 This is free software; you can redistribute it and/or modify it under
 the same terms as the Perl 5 programming language system itself.
@@ -6,10 +6,15 @@ use Test::More 0.88;
 use Test::Deep;
 
 {
-  my $logger = Log::Dispatchouli->new_tester({ log_pid => 1 });
+  my $logger = Log::Dispatchouli->new_tester({
+    log_pid => 1,
+    ident   => 't/basic.t',
+  });
 
   isa_ok($logger, 'Log::Dispatchouli');
 
+  is($logger->ident, 't/basic.t', '$logger->ident is available');
+
   $logger->log([ "point: %s", {x=>1,y=>2} ]);
   $logger->log_debug('this will not get logged');
 
@@ -0,0 +1,44 @@
+#!perl
+use strict;
+use warnings;
+
+use Test::More;
+
+use Log::Dispatchouli;
+
+{
+  package Xyzzy::Logger;
+  use base 'Log::Dispatchouli';
+
+  sub env_prefix { 'XYZZY' }
+}
+
+{
+  local $ENV{DISPATCHOULI_DEBUG} = 1;
+  local $ENV{XYZZY_DEBUG} = 0;
+  my $d_logger = Log::Dispatchouli->new_tester;
+  my $x_logger = Xyzzy::Logger->new_tester;
+
+  ok(   $d_logger->is_debug, "DISPATCHOULI_ affects L::D logger");
+  ok( ! $x_logger->is_debug, "...but XYZZY_ overrides for X::L");
+}
+
+{
+  local $ENV{DISPATCHOULI_DEBUG} = 1;
+  my $d_logger = Log::Dispatchouli->new_tester;
+  my $x_logger = Xyzzy::Logger->new_tester;
+
+  ok(   $d_logger->is_debug, "DISPATCHOULI_ affects L::D logger");
+  ok(   $x_logger->is_debug, "...and X::L will use it with no XYZZY_");
+}
+
+{
+  local $ENV{XYZZY_DEBUG} = 1;
+  my $d_logger = Log::Dispatchouli->new_tester;
+  my $x_logger = Xyzzy::Logger->new_tester;
+
+  ok(   $x_logger->is_debug, "XYZZY_ affects X::L");
+  ok( ! $d_logger->is_debug, "...but not L::D");
+}
+
+done_testing;
@@ -0,0 +1,40 @@
+use strict;
+use warnings;
+use Test::More;
+
+use Scalar::Util qw(refaddr);
+
+use lib 't/lib';
+
+# DDR - default default ref -- uses the default default_logger_ref
+{ package DDR_P; use DDR::Parent '$Logger'; }
+{ package DDR_C; use DDR::Child  '$Logger'; }
+
+# SDR - shared default ref -- uses a default_logger_ref shared between classes
+{ package SDR_P; use SDR::Parent '$Logger'; }
+{ package SDR_C; use SDR::Child  '$Logger'; }
+
+is(
+  refaddr( $DDR_P::Logger ),
+  refaddr( $DDR_C::Logger ),
+  "DDR parent and child share logger storage",
+);
+
+# DDR::Child can store its default in a different place, but
+# $DDR::Parent::Logger is already defined when we get here, so the logic is
+# "already defined and not equal to *my* default, so it is untouched."
+is($DDR_P::Logger->ident, 'DDR::Parent', "parent won the initialization race");
+
+is(
+  refaddr( $SDR_P::Logger ),
+  refaddr( $SDR_C::Logger ),
+  "SDR parent and child share logger storage",
+);
+
+is(
+  $SDR_P::Logger->ident,
+  'SDR::Parent',
+  "SDR::Parent is initialized first, so its default wins",
+);
+
+done_testing;
@@ -0,0 +1,54 @@
+use strict;
+use warnings;
+
+use Test::Fatal;
+use Test::More;
+
+use Log::Dispatchouli::Global '$Logger' => { init => {
+  ident   => 't/global.t',
+  log_pid => 0,
+  to_self => 1,
+}};
+
+{
+  package Alpha;
+  use Log::Dispatchouli::Global '$Logger';
+
+  sub call_bravo {
+    my ($self, $n) = @_;
+    
+    local $Logger = $Logger->proxy({ proxy_prefix => "$n: " });
+
+    $Logger->log("inside call_bravo");
+
+    Bravo->endpoint;
+  }
+}
+
+{
+  package Bravo;
+  use Log::Dispatchouli::Global '$Logger' => { -as => 'L' };
+
+  sub endpoint {
+    my ($self, $n) = @_;
+    
+    $L->log("inside Bravo::endpoint");
+  }
+}
+
+isa_ok($Logger, 'Log::Dispatchouli', 'imported $Logger');
+
+$Logger->log("first");
+
+Alpha->call_bravo(123);
+
+$Logger->log("last");
+
+my $events = $Logger->events;
+
+is($events->[0]->{message}, 'first', '1st log');
+is($events->[1]->{message}, '123: inside call_bravo', '2nd log');
+is($events->[2]->{message}, '123: inside Bravo::endpoint', '3rd log');
+is($events->[3]->{message}, 'last', '4th log');
+
+done_testing;
@@ -0,0 +1,11 @@
+use strict;
+package DDR::Child;
+use base 'DDR::Parent';
+sub default_logger_args {
+  return {
+    ident   => __PACKAGE__,
+    log_pid => 0,
+    to_self => 1,
+  }
+}
+1;
@@ -0,0 +1,12 @@
+use strict;
+package DDR::Parent;
+use base 'Log::Dispatchouli::Global';
+sub logger_globref { no warnings 'once'; \*Logger }
+sub default_logger_args {
+  return {
+    ident   => __PACKAGE__,
+    log_pid => 0,
+    to_self => 1,
+  }
+}
+1;
@@ -0,0 +1,11 @@
+use strict;
+package SDR::Child;
+use base 'SDR::Parent';
+sub default_logger_args {
+  return {
+    ident   => __PACKAGE__,
+    log_pid => 0,
+    to_self => 1,
+  }
+}
+1;
@@ -0,0 +1,15 @@
+use strict;
+package SDR::Parent;
+use base 'Log::Dispatchouli::Global';
+sub logger_globref { no warnings 'once'; \*Logger }
+
+my $default_logger;
+sub default_logger_ref { \$default_logger }
+sub default_logger_args {
+  return {
+    ident   => __PACKAGE__,
+    log_pid => 0,
+    to_self => 1,
+  }
+}
+1;
@@ -4,7 +4,9 @@ use warnings;
 use Log::Dispatchouli;
 use Test::More 0.88;
 
-my $logger = Log::Dispatchouli->new_tester;
+my $logger = Log::Dispatchouli->new_tester({
+  ident => 't/proxy.t',
+});
 
 sub are_events {
   my ($comment, $want) = @_;
@@ -17,6 +19,8 @@ sub are_events {
 
 $logger->log("1");
 
+is($logger->ident, 't/proxy.t', '$logger->ident is available');
+
 are_events("we can log a simple event", [ '1' ]);
 
 $logger->set_prefix("A: ");
@@ -30,6 +34,8 @@ my $proxy = $logger->proxy({
   proxy_prefix => 'B: ',
 });
 
+is($proxy->ident, 't/proxy.t', '$proxy->ident is available');
+
 $proxy->log("3");
 
 are_events("log with proxy with prefix", [
@@ -85,7 +91,7 @@ $logger->log_debug("logger debug");
 $proxy->log_debug("proxy debug");
 $proxprox->log_debug("proxprox debug");
 
-are_events("debugging in middle tier", [
+are_events("debugging in middle tier (middle set_debug)", [
   'A: B: C: proxy debug',
   'A: B: C: E: F: proxprox debug',
 ]);